#include <stdio.h>
#include <assert.h>

#include "bitmap_impl.h"
#include "agg/pixel_formats.h"
#include "agg/agg_renderer_base.h"

namespace visgrph
{

// implementation of bitmap
bitmap::bitmap()
: impl(NULL)
{
}

bitmap::~bitmap()
{
	if (impl)
	{
		impl->release();
		impl = NULL;
	}
}

bitmap_impl* bitmap::inst(void)
{
	if (NULL == impl)
	{
		impl = new bitmap_impl();
		if (NULL == impl)
			return NULL;
	}
	return impl;
}

bool bitmap::create(uint width, uint height, uint stride)
{
	bitmap_impl *bi = inst();
	if (!bi) return false;
	return bi->create(width, height, stride);
}

bool bitmap::attach(void* buf, uint width, uint height, uint stride)
{
	bitmap_impl *bi = inst();
	if (!bi) return false;
	return bi->attach(buf, width, height, stride);
}

bitmap_impl::~bitmap_impl()
{
	reset_buffer(NULL);
}

int bitmap_impl::addref(void)
{
	assert(m_refcnt);
	return ++m_refcnt;
}

void bitmap_impl::reset_buffer(void* buf)
{
	// todo: check if any other release way to be added
	if (m_target &&
		!(m_flags & bmp_imp_flag_attached_buf))
		delete [] (agg::int8u*)m_target;
	m_target = buf;
}

int bitmap_impl::release(void)
{
	int tmp = --m_refcnt;
	if (!tmp) delete this;
	return tmp;
}

bool bitmap_impl::create(uint width, uint height, uint stride)
{
	if (!width || !height || !stride)
		return false;

	if (stride < width * 4)
		return false;

	// make sure it is 128bit aligned
	if (stride & 15) return false;

	m_syncobj.sync_start();
	agg::int8u* tmp = new agg::int8u [height * stride];
	if (NULL == tmp)
	{
		m_syncobj.sync_end();
		return false;
	}
	reset_buffer(reinterpret_cast<void*>(tmp));
	m_width = width;
	m_height = height;
	m_stride = stride;
	m_syncobj.sync_end();
	return true;
}

bool bitmap_impl::attach(void* buf, uint width, uint height, uint stride)
{
	if (!buf || !width || !height || !stride)
		return false;

	if (stride < width * 4)
		return false;

	// make sure it is 128bit aligned
	if (stride & 15) return false;

	m_syncobj.sync_start();
	reset_buffer(buf);
	m_flags |= bmp_imp_flag_attached_buf;
	m_width = width;
	m_height = height;
	m_stride = stride;
	m_syncobj.sync_end();
	return true;
}

}; // namespace visgrph
/* EOF */
